package ongd.servicios.persistencia;

import java.io.Serializable;
import javax.persistence.EntityManager;
import javax.persistence.EntityNotFoundException;
import ongd.negocio.gestion.Indice;
import java.util.ArrayList;
import java.util.List;
import ongd.negocio.gestion.Entidad;
import ongd.servicios.persistencia.exceptions.NonexistentEntityException;
import ongd.servicios.persistencia.exceptions.PreexistingEntityException;

/**
 * Clase que contiene los método que para realizar operaciones
 * sobre la base de datos referente a la entidad indice.
 *
 * @author <a href="mailto:egi0002@alu.ubu.es">Elena García Iglesias</a>
 * @author <a href="mailto:cms0021@alu.ubu.es">Cristina Martínez Sanz</a>
 * @version 1.0 20120124
 *
 */
public class IndiceJpaController extends AJPAControlador implements Serializable {

    /**
     * Objeto de tipo EntityManager.
     */
    private EntityManager em = null;

    /**
     * Constructor de la clase.
     * @param em EntityManager
     */
    public IndiceJpaController(EntityManager em) {
        this.em = em;
    }

    /**
     * Método que crea un objeto de tipo indice en la base de datos.
     * @param entidad Objeto que crearemos 
     * @param et Booleano que indica si hay que iniciar la transacción
     * @throws PreexistingEntityException
     * @throws Exception 
     */
    @Override
    public void create(Entidad entidad, boolean et) throws PreexistingEntityException, Exception {
        Indice indice = (Indice) entidad;
        if (indice.getIndiceList() == null) {
            indice.setIndiceList(new ArrayList<Indice>());
        }
        try {
            //si et es falso significa que tengo que crear la transacción
            if (!et) {
                em.getTransaction().begin();
            }
            Indice indiceidIndice = indice.getIndiceidIndice();
            if (indiceidIndice != null) {
                indiceidIndice = em.getReference(indiceidIndice.getClass(), indiceidIndice.getIdIndice());
                indice.setIndiceidIndice(indiceidIndice);
            }
            List<Indice> attachedIndiceList = new ArrayList<Indice>();
            for (Indice indiceListIndiceToAttach : indice.getIndiceList()) {
                indiceListIndiceToAttach = em.getReference(indiceListIndiceToAttach.getClass(), indiceListIndiceToAttach.getIdIndice());
                attachedIndiceList.add(indiceListIndiceToAttach);
            }
            indice.setIndiceList(attachedIndiceList);
            em.persist(indice);
            if (indiceidIndice != null) {
                indiceidIndice.getIndiceList().add(indice);
                indiceidIndice = em.merge(indiceidIndice);
            }
            for (Indice indiceListIndice : indice.getIndiceList()) {
                Indice oldIndiceidIndiceOfIndiceListIndice = indiceListIndice.getIndiceidIndice();
                indiceListIndice.setIndiceidIndice(indice);
                indiceListIndice = em.merge(indiceListIndice);
                if (oldIndiceidIndiceOfIndiceListIndice != null) {
                    oldIndiceidIndiceOfIndiceListIndice.getIndiceList().remove(indiceListIndice);
                    oldIndiceidIndiceOfIndiceListIndice = em.merge(oldIndiceidIndiceOfIndiceListIndice);
                }
            }
            //Si et es falso significa que tengo que terminar la transaccion
            if (!et) {
                em.getTransaction().commit();
            }
        } catch (Exception ex) {
            if (findEntidad(Indice.class, indice.getIdIndice()) != null) {
                throw new PreexistingEntityException("Indice " + indice + " already exists.", ex);
            }
            throw ex;
        } finally {
            if (em != null) {
//                em.close();
            }
        }
    }

    /**
     * Método que edita un objeto de tipo indice en la base de datos.
     * @param entidad Entidad que editaremos
     * @param et Booleano que indica si hay que iniciar la transacción
     * @throws NonexistentEntityException
     * @throws Exception 
     */
    @Override
    public void edit(Entidad entidad, boolean et) throws NonexistentEntityException, Exception {
        Indice indice = (Indice) entidad;
        try {
            //Si et es falso significa que tengo que crear la transacción
            if (!et) {
                em.getTransaction().begin();
            }
            Indice persistentIndice = em.find(Indice.class, indice.getIdIndice());
            Indice indiceidIndiceOld = persistentIndice.getIndiceidIndice();
            Indice indiceidIndiceNew = indice.getIndiceidIndice();
            List<Indice> indiceListOld = persistentIndice.getIndiceList();
            List<Indice> indiceListNew = indice.getIndiceList();
            if (indiceidIndiceNew != null) {
                indiceidIndiceNew = em.getReference(indiceidIndiceNew.getClass(), indiceidIndiceNew.getIdIndice());
                indice.setIndiceidIndice(indiceidIndiceNew);
            }
            List<Indice> attachedIndiceListNew = new ArrayList<Indice>();
            for (Indice indiceListNewIndiceToAttach : indiceListNew) {
                indiceListNewIndiceToAttach = em.getReference(indiceListNewIndiceToAttach.getClass(), indiceListNewIndiceToAttach.getIdIndice());
                attachedIndiceListNew.add(indiceListNewIndiceToAttach);
            }
            indiceListNew = attachedIndiceListNew;
            indice.setIndiceList(indiceListNew);
            indice = em.merge(indice);
            if (indiceidIndiceOld != null && !indiceidIndiceOld.equals(indiceidIndiceNew)) {
                indiceidIndiceOld.getIndiceList().remove(indice);
                indiceidIndiceOld = em.merge(indiceidIndiceOld);
            }
            if (indiceidIndiceNew != null && !indiceidIndiceNew.equals(indiceidIndiceOld)) {
                indiceidIndiceNew.getIndiceList().add(indice);
                indiceidIndiceNew = em.merge(indiceidIndiceNew);
            }
            for (Indice indiceListOldIndice : indiceListOld) {
                if (!indiceListNew.contains(indiceListOldIndice)) {
                    indiceListOldIndice.setIndiceidIndice(null);
                    indiceListOldIndice = em.merge(indiceListOldIndice);
                }
            }
            for (Indice indiceListNewIndice : indiceListNew) {
                if (!indiceListOld.contains(indiceListNewIndice)) {
                    Indice oldIndiceidIndiceOfIndiceListNewIndice = indiceListNewIndice.getIndiceidIndice();
                    indiceListNewIndice.setIndiceidIndice(indice);
                    indiceListNewIndice = em.merge(indiceListNewIndice);
                    if (oldIndiceidIndiceOfIndiceListNewIndice != null && !oldIndiceidIndiceOfIndiceListNewIndice.equals(indice)) {
                        oldIndiceidIndiceOfIndiceListNewIndice.getIndiceList().remove(indiceListNewIndice);
                        oldIndiceidIndiceOfIndiceListNewIndice = em.merge(oldIndiceidIndiceOfIndiceListNewIndice);
                    }
                }
            }
            //Si et es falso significa que tengo que terminar la transaccion
            if (!et) {
                em.getTransaction().commit();
            }
        } catch (Exception ex) {
            String msg = ex.getLocalizedMessage();
            if (msg == null || msg.length() == 0) {
                Integer id = indice.getIdIndice();
                if (findEntidad(Indice.class, id) == null) {
                    throw new NonexistentEntityException("The indice with id " + id + " no longer exists.");
                }
            }
            throw ex;
        } finally {
            if (em != null) {
//                em.close();
            }
        }
    }

    /**
     * Método que borra un objeto de tipo indice de la base de datos.
     * @param clase Clase correpondiente al objeto a borrar
     * @param id Clave primaria del objeto a borrar
     * @param et Booleano que indica si hay que iniciar la transaccion
     * @throws NonexistentEntityException 
     */
    @Override
    public void destroy(Class clase, Object id, boolean et) throws NonexistentEntityException {
        try {
            //Si et es falso significa que tengo que crear la transacción
            if (!et){
                em.getTransaction().begin();
            }
            Indice indice;
            try {
                indice = (Indice) em.getReference(clase, id);
                indice.getIdIndice();
            } catch (EntityNotFoundException enfe) {
                throw new NonexistentEntityException("The indice with id " + id + " no longer exists.", enfe);
            }
            Indice indiceidIndice = indice.getIndiceidIndice();
            if (indiceidIndice != null) {
                indiceidIndice.getIndiceList().remove(indice);
                indiceidIndice = em.merge(indiceidIndice);
            }
            List<Indice> indiceList = indice.getIndiceList();
            for (Indice indiceListIndice : indiceList) {
                indiceListIndice.setIndiceidIndice(null);
                indiceListIndice = em.merge(indiceListIndice);
            }
            em.remove(indice);
            //Si et es falso significa que tengo que terminar la transaccion
            if (!et) {
                em.getTransaction().commit();
            }
        } finally {
            if (em != null) {
//                em.close();
            }
        }
    }

    /**
     * Método que busca un indice en la base de datos.
     * @param cls Class correspondiente al objeto a buscar
     * @param id Clave primaria del objeto a buscar
     * @return indice
     */
    @Override
    public Indice findEntidad(Class cls, Object id) {
        try {
            return (Indice) em.find(cls, id);
        } finally {
//            em.close();
        }
    }
}
